// hdu5470
// 题意：给定长度为n(<=100000)的目标串，要从空串产生这个目标串，可以有两种
//       操作：
//        1.向已有的串后面加一个字母，费用为对应字母的费用;
//        2.或者在已有的字符串里选择连续一段复制粘贴一次（粘贴完就无效）到末尾，
//        选择一个字母的费用是A，复制和粘贴的费用都是B。
//       问最后生成目标串，最小费用。
//
// 题解：good prob. 很明显是个dp, 设f[i]表示打好前i个串的费用，
//       第一个操作：
//         f[i] = f[i - 1] + cost[s[i]]
//       第二个操作
//         f[i] = min{f[j] + (i - j) * A + 2*B}
//              = min{f[j] - j * A + i*A + 2*B}其中(j, i]是[0, j]的子串，
//       我们可以发现，对于每个位置i，若最小的left[i]使得[left[i], i]是
//       前面的子串，那么对于left[i]之后的都是前面的子串，然后f[j] - j*A
//       这个式子又是和i无关的，那么可以用单调队列来维护。
//
//       现在就是这个left[i]如何求。
//       我们可以用后缀自动机，这里细节比较麻烦。
//       我们考虑做到了当前第i位，然后前left[i]个都加到后缀自动机里，
//       如果当前i+1位在我们维护的之前最后状态last还有边，那么
//       left[i+1]=left[i]，否则我们把left[i]这位加到后缀自动机里，
//       不断沿着后缀链接(link, or fail)求当前last结尾的最长后缀，然后
//       判断有没有边指向s[i+1]，一直这么做。。
//
//       比较恶心。
//
// run: $exec < bfdiff.in
// opt: 0
// flag: -g
#include <algorithm>
#include <cstdio>
#include <cstring>

#define _DEBUG

int const alpha_size = 26;
int const maxn = 100010;

struct state
{
	int len;
	state * link, * child[alpha_size + 4];
} sam_state[maxn * 30], * sam_head, * sam_last, * last;

int sam_alloc;

struct monoq_state { long long v; int pos; };

long long cost[alpha_size];
char s[maxn];
long long costa, costb;

long long f[maxn];
int left[maxn];
monoq_state monoq[4 * maxn];
int n;

state * sam_state_alloc()
{
	state * tmp = sam_state + sam_alloc++;
	std::memset(tmp->child, 0, sizeof(tmp->child));
	tmp->link = NULL;
	return tmp;
}

state * sam_extend(state * sam_last, int x)
{
	state * cur = sam_state_alloc();
	cur->len = sam_last->len + 1;
	state * p;
	for (p = sam_last; p && !p->child[x]; p = p->link)
		p->child[x] = cur;
	if (!p) cur->link = sam_head;
	else {
		state * q = p->child[x];
		if (p->len + 1 == q->len)
			cur->link = q;
		else {
			state * clone = sam_state_alloc();
			*clone = *q;
			clone->len = p->len + 1;

			if (last == q) last = clone; // FIXME special

			for (; p && p->child[x] == q; p = p->link)
				p->child[x] = clone;
			q->link = cur->link = clone;
		}
	}
	return cur;
}

void init()
{
	sam_alloc = 1;
	last = sam_last = sam_head = sam_state_alloc();
	sam_head->len = 0;
}

int main()
{
	int T;  std::scanf("%d", &T);
	for (int ti = 1; ti <= T; ti++) {
		std::printf("Case #%d: ", ti);
		std::scanf("%s", s);
		n = std::strlen(s);

		init();
		for (int i = 0; i < alpha_size; i++)
			std::scanf("%lld", &cost[i]);
		std::scanf("%lld %lld", &costa, &costb);
		costb *= 2;

		int pos = 0, len = 0;
		for (int i = 0; i < n; i++) {
			int index = s[i] - 'a';
			while (pos < i && !last->child[index]) {
				sam_last = sam_extend(sam_last, s[pos++] - 'a');
				if (last != sam_head && --len == last->link->len)
					last = last->link;
	//			std::printf("%d\n", (last == sam_head));
			}
			if (last->child[index]) {
				last = last->child[index]; len++;
			} else {
				sam_last = sam_extend(sam_last, s[pos++] - 'a');
				last = sam_head;
			}
//			std::printf("i = %d   j = %d\n", i + 1, pos);
			left[i] = pos;
		}

#ifdef __DEBUG
		for (int i = 0; i < n; i++)
			std::printf(" i = %d  left[i] = %d\n", i, left[i]);
#endif

		f[1] = cost[s[0] - 'a'];
		monoq_state first; first.pos = 1; first.v = f[1] - costa;
		int head = 1, tail = 1;
		monoq[head] = first;
		for (int i = 2; i <= n; i++) {
			f[i] = f[i - 1] + cost[s[i - 1] - 'a'];
			long long tmp = i * costa + costb;
			while (head <= tail && monoq[head].pos < left[i - 1]) head++;
			if (head <= tail) {
				tmp += monoq[head].v;
				f[i] = std::min(f[i], tmp);
			}
			tmp = f[i] - i * costa;
			while (head <= tail && monoq[tail].v >= tmp) tail--;
			monoq_state add; add.pos = i; add.v = tmp;
			monoq[++tail] = add;
//			std::printf("f[%d] = %lld\n", i, f[i]);
		}
		std::printf("%lld\n", f[n]);
	}
}

